import random
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from game import *


SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
BLOCK_SIZE = 20

# 记录了每个方向对应的蛇头移动距离
MOVE_DICT = {
    Qt.Key_Left:    (-1, 0),
    Qt.Key_Right:   (1, 0),
    Qt.Key_Up:      (0, -1),
    Qt.Key_Down:    (0, 1)
}
# 记录了每个方向对应的蛇头图片旋转角度
DIRECTION_HEAD_ANGLE = {
    Qt.Key_Left:    90,
    Qt.Key_Right:   270,
    Qt.Key_Up:      180,
    Qt.Key_Down:    0
}

class Snake:
    
    def __init__(self) -> None:
        # 当前蛇头运动方向
        self.direction = Qt.Key_Right
        # 根据按键获取的最新蛇头运动方向
        self.direction_temp = None
        # 加载并缩放蛇头
        self.head_img: QImage = QImage("img/head-red.png").scaled(BLOCK_SIZE, BLOCK_SIZE)
        # 初始化蛇
        self.snake_body = [
            [3 * BLOCK_SIZE, 3 * BLOCK_SIZE],
        ]
        # 生长2节
        self.score = 0
        self.grow()
        self.grow()
        
    def handle_key_event(self, event: QKeyEvent) -> bool:
        """判定按钮是否是方向的按键
        并且判定能否改变到此方向

        :param event: 按键事件
        :return: True 能转向
        """
        key = event.key()
        LR = Qt.Key_Left , Qt.Key_Right
        UD = Qt.Key_Up, Qt.Key_Down
        
        if key not in LR and key not in UD:
            return False
        
        if key in LR and self.direction in LR:
            return False
    
        if key in UD and self.direction in UD:
            return False
        
        self.direction_temp = key
        return True
    
    def draw(self, qp: QPainter):
        """绘制蛇头蛇身

        :param qp: 画笔
        """
        qp.setBrush(COLOR_BLUE)        
        for node in self.snake_body[1:]:
            # 绘制圆角矩形
            # qp.drawRect(node[0], node[1], BLOCK_SIZE, BLOCK_SIZE)
            qp.drawRoundedRect(node[0], node[1], BLOCK_SIZE, BLOCK_SIZE, 5, 5)
    
        qp.setBrush(QColor(0, 255, 0))
        head = self.snake_body[0]
        # qp.drawRect(self.snake_body[0][0], head[1], BLOCK_SIZE, BLOCK_SIZE)
        # 根据direction修改head_img旋转方向
        rotated_head = self.head_img.transformed(QTransform().rotate(DIRECTION_HEAD_ANGLE[self.direction]))
        qp.drawImage(head[0], head[1], rotated_head)
    
    def move(self):
        """移动一格
        """
        if self.direction_temp:
            self.direction = self.direction_temp
            self.direction_temp = None
        
        # 修改头部坐标
        new_head = self.snake_body[0][:]
        new_move = MOVE_DICT[self.direction]
        new_head[0] += new_move[0] * BLOCK_SIZE
        new_head[1] += new_move[1] * BLOCK_SIZE
        self.snake_body.insert(0, new_head)
        
        # 删除尾部坐标
        self.snake_body.pop()
        
    def grow(self):
        # 取出尾部坐标, 并复制一份
        new_tail = self.snake_body[-1][:]
        # 插入到尾部
        self.snake_body.append(new_tail)
        
class Apple:
    
    def __init__(self, x, y) -> None:
        self.node = [x * BLOCK_SIZE, y * BLOCK_SIZE]

    def draw(self, qp: QPainter):
        qp.setBrush(QColor(255, 0, 0))
        qp.drawRect(self.node[0], self.node[1], BLOCK_SIZE, BLOCK_SIZE)

class SnakeGame(Game):
    
    def __init__(self):
        super().__init__()
        
        # 设置窗口尺寸, 并禁止拖拽修改窗口尺寸
        self.setFixedSize(SCREEN_WIDTH, SCREEN_HEIGHT)
        # 设置窗口标题
        self.setWindowTitle("Snake Game")
        # 图标
        self.setWindowIcon(QIcon("img/icon.png"))
        
        # 加载背景图, (缩放)
        self.background_img = QImage("img/bg.png").scaled(SCREEN_WIDTH, SCREEN_HEIGHT)
        
        # 设置fps，每秒5帧， 1000ms / 5 = 200ms
        self.set_fps(5)
        
        self.snake = None
        self.apple = None
        
        # 构建地图格点的二维数组
        self.map = []
        for i in range(SCREEN_WIDTH // BLOCK_SIZE):
            for j in range(SCREEN_HEIGHT // BLOCK_SIZE):
                self.map.append([i, j])
                
        
    def keyPressEvent(self, event: QKeyEvent):
        if self.snake.handle_key_event(event):
            return
        super().keyPressEvent(event)
        
    def on_time_event(self, event: QTimerEvent):
        """处理每帧时间事件

        :param event: 事件
        """
        self.snake.move()
        self.check_collision()
    
    def draw_content(self, qp: QPainter):
        # 绘制背景图
        qp.drawImage(0, 0, self.background_img)
        
        # 绘制网格线，间隔为BLOCK_SIZE
        # 设置画笔为灰色
        qp.setPen(COLOR_GRAY)
        # 绘制横线. 
        # (0, 0) -> (SCREEN_WIDTH, 0)
        # (0,20) -> (SCREEN_WIDTH, 20)
        for y in range(0, SCREEN_HEIGHT, BLOCK_SIZE):
            qp.drawLine(0, y, SCREEN_WIDTH, y)
        # 绘制纵线
        for x in range(0, SCREEN_WIDTH, BLOCK_SIZE):
            qp.drawLine(x, 0, x, SCREEN_HEIGHT)
        
        self.snake.draw(qp)
        self.apple.draw(qp)
        
        # 绘制文字
        qp.setPen(COLOR_WHITE)
        # 设置字号22, 字体 Arial
        qp.setFont(QFont("Arial", 18))
        # 左上角得分 Score: xxx
        qp.drawText(20, 30, f"Score: {self.snake.score}")
        
        if self.is_game_over:
            # 设置字号20, 字体 Microsoft YaHei
            qp.setFont(QFont("Microsoft YaHei", 20, weight=QFont.Bold))
            # Game Over
            qp.drawText(SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2, "游戏结束")
            qp.setFont(QFont("Microsoft YaHei", 14))
            qp.drawText(SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 + 40, "得分：" + str(self.snake.score))
            qp.drawText(SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 + 70, "按空格重新开始")
        
        
    def check_collision(self):
        """碰撞检测
        """
        snake_head = self.snake.snake_body[0]
        if snake_head == self.apple.node:
            print("吃到苹果")
            self.generate_new_apple()
            self.snake.grow()
            self.snake.score += 1
            
        # 如果蛇身占满地图，游戏结束
        if len(self.snake.snake_body) >= len(self.map):
            print("游戏胜利")
            self.is_game_over = True
        
        # 碰到自己
        if snake_head in self.snake.snake_body[1:]:
            self.is_game_over = True
            print("碰到自己")
            
        # 碰到墙
        head_x, head_y = snake_head
        if head_x < 0 or head_x >= SCREEN_WIDTH or head_y < 0 or head_y >= SCREEN_HEIGHT:
            self.is_game_over = True
            print("碰到墙")
            
    def generate_new_apple(self):
        """生成新的苹果坐标
        """
        # 复制一份self.map为新的temp_map
        temp_map = self.map[:]
        
        # 将 temp_map 中snake的坐标删除
        for node in self.snake.snake_body:
            node_pos = [node[0] // BLOCK_SIZE, node[1] // BLOCK_SIZE]
            if node_pos in temp_map:
                temp_map.remove(node_pos)
            
        if len(temp_map) == 0:
            return
            
        # 生成新的苹果坐标
        new_pos = random.choice(temp_map)
        print("new_pos: ", new_pos)
        self.apple = Apple(new_pos[0], new_pos[1])
        
    def start_game(self):
        self.snake = Snake()
        # self.apple = Apple(2, 2)
        self.generate_new_apple()
        
        super().start_game()
        
        
if __name__ == "__main__":
    SnakeGame.start()